#!/bin/bash

BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
PROJECT_DIR=$(dirname ${BASE_DIR})

. "${BASE_DIR}/utils.sh"

DOCKER_CONFIG="/etc/docker/daemon.json"
docker_config_change=0
docker_copy_failed=0

function prepare_docker_bin() {
  md5_matched=$(check_md5 /tmp/docker.tar.gz "${DOCKER_MD5}")
  if [[ ! -f /tmp/docker.tar.gz || "${md5_matched}" != "1" ]]; then
    prepare_online_install_required_pkg
    get_file_md5 /tmp/docker.tar.gz
    echo "Starting to download Docker engine ..."
    wget -q "${DOCKER_BIN_URL}" -O /tmp/docker.tar.gz || {
      log_error "Download docker fails, check the network is normal"
      exit 1
    }
  else
    echo "Using Docker cache: /tmp/docker.tar.gz"
  fi
  cp /tmp/docker.tar.gz . && tar xzf docker.tar.gz && rm -f docker.tar.gz
  chmod +x docker/*
}

function copy_docker() {
  \cp -f ./docker/* /usr/bin/ \
  && \cp -f ./docker.service /etc/systemd/system/ \
  && chmod 755 /usr/bin/docker* \
  && chmod 755 /etc/systemd/system/docker.service
  if [[ "$?" != "0" ]]; then
    docker_copy_failed=1
  fi
}

function install_docker() {
  if [[ ! -f ./docker/dockerd ]]; then
    prepare_docker_bin
  fi
  if [[ ! -f ./docker/dockerd ]]; then
    echo_red "Error: Docker program does not exist"
    exit 1
  fi

  docker_exist=1
  docker_version_match=1
  old_docker_md5=$(get_file_md5 /usr/bin/dockerd)
  new_docker_md5=$(get_file_md5 ./docker/dockerd)

  if [[ ! -f "/usr/bin/dockerd" ]]; then
    docker_exist=0
  elif [[ "${old_docker_md5}" != "${new_docker_md5}" ]]; then
    docker_version_match=0
  fi

  if [[ "${docker_exist}" != "1" ]]; then
    copy_docker
  elif [[ "${docker_version_match}" != "1" ]]; then
    confirm="n"
    read_from_input confirm "There are updates available currently. Do you want to update?" "y/n" "${confirm}"
    if [[ "${confirm}" == "y" ]]; then
      copy_docker
    fi
  fi

  if [[ "${docker_copy_failed}" != "0" ]]; then
    echo_red "Docker file copy failed. May be that docker service is already running. Please stop the running docker and re-execute it"
    echo_red "systemctl stop docker"
    exit 1
  fi
  echo_done
}

function check_docker_install() {
  command -v docker > /dev/null || {
    install_docker
  }
}


function prepare_compose_bin() {
  md5_matched=$(check_md5 /tmp/docker-compose "${DOCKER_COMPOSE_MD5}")
  if [[ ! -f /tmp/docker-compose || "${md5_matched}" != "1" ]]; then
    prepare_online_install_required_pkg
    get_file_md5 /tmp/docker-compose
    echo "Starting to download Docker Compose binary ..."
    wget -q "${DOCKER_COMPOSE_BIN_URL}" -O /tmp/docker-compose || {
      log_error "Download docker-compose fails, check the network is normal"
      exit 1
    }
  else
    echo "Using Docker Compose cache: /tmp/docker-compose"
  fi
  if [[ ! -d "$BASE_DIR/docker" ]]; then
    mkdir -p ${BASE_DIR}/docker
  fi
  cp /tmp/docker-compose docker/
  chmod +x docker/*
  export PATH=$PATH:$(pwd)/docker
}

function install_compose() {
  if [[ ! -f ./docker/docker-compose ]]; then
    prepare_compose_bin
  fi
  old_docker_compose_md5=$(get_file_md5 /usr/bin/docker-compose)
  new_docker_compose_md5=$(get_file_md5 ./docker/docker-compose)
  if [[ ! -f "/usr/bin/docker-compose" || "${old_docker_compose_md5}" != "${new_docker_compose_md5}" ]]; then
    \cp -f ./docker/docker-compose /usr/bin/
    chmod +x /usr/bin/docker-compose
  fi
  echo_done
}

function check_compose_install() {
  command -v docker-compose > /dev/null && echo_done || {
    install_compose
  }
}


function set_docker_config() {
  key=$1
  value=$2

  if [[ ! -f "${DOCKER_CONFIG}" ]]; then
    config_dir=$(dirname ${DOCKER_CONFIG})
    if [[ ! -d ${config_dir} ]]; then
      mkdir -p "${config_dir}"
    fi
    echo -e "{\n}" >>${DOCKER_CONFIG}
  fi
  $(python -c "import json
key = '${key}'
value = '${value}'
try:
    value = json.loads(value)
except:
    pass
filepath = \"${DOCKER_CONFIG}\"
f = open(filepath);
config = json.load(f);
config[key] = value
f.close();
f = open(filepath, 'w');
json.dump(config, f, indent=True, sort_keys=True);
f.close()
")
}

function config_docker() {
  docker_storage_path=$(get_config DOCKER_DIR)
  if [[ -z "${docker_storage_path}" ]]; then
    docker_storage_path="/var/lib/docker"
  fi
  confirm="n"
  read_from_input confirm "Do you need custom docker root dir, will use the default directory ${docker_storage_path}?" "y/n" "${confirm}"

  if [[ "${confirm}" == "y" ]]; then
    echo
    echo "Modify the default storage directory of Docker image, you can select your largest disk and create a directory in it, such as /opt/docker"
    df -h | egrep -v "map|devfs|tmpfs|overlay|shm"
    echo
    read_from_input docker_storage_path "Docker image storage directory: ${docker_storage_path}"
  fi

  if [[ ! -d "${docker_storage_path}" ]]; then
    mkdir -p "${docker_storage_path}"
  fi
  set_config DOCKER_DIR "${docker_storage_path}"

  set_docker_config registry-mirrors '["https://registry.docker-cn.com"]'
  set_docker_config insecure-registries '["registry.access.redhat.com", "quay.io"]'
  set_docker_config live-restore "true"
  set_docker_config data-root "${docker_storage_path}"
  set_docker_config log-driver "json-file"
  set_docker_config log-opts '{"max-size": "10m", "max-file": "3"}'
  diff /etc/docker/daemon.json /etc/docker/daemon.json.bak &>/dev/null
  if [[ "$?" != "0" ]]; then
    docker_config_change=1
  fi
  echo_done
}

function check_docker_config() {
  if [[ ! -f "/etc/docker/daemon.json" ]]; then
    config_docker
  else
    echo_done
  fi
}


function start_docker() {
  if command -v systemctl > /dev/null; then
    systemctl daemon-reload
    systemctl enable docker
    systemctl start docker
  fi
  docker ps >/dev/null 2>&1
  if [[ "$?" == "0" ]]; then
    echo_done
  else
    echo_failed
    exit 1
  fi
}

function prepare_set_redhat_firewalld() {
  if [[ -f "/etc/redhat-release" ]]; then
    firewall-cmd --state > /dev/null 2>&1
    if [[ "$?" == "0" ]]; then
      docker_subnet=$(get_config DOCKER_SUBNET)
      if [[ ! "$(firewall-cmd --list-rich-rule | grep ${docker_subnet})" ]]; then
        firewall-cmd --permanent --zone=public --add-rich-rule="rule family=ipv4 source address=${docker_subnet} accept"
        firewall-cmd --reload
      fi
      if command -v dnf > /dev/null; then
        if [[ ! "$(firewall-cmd --list-all | grep 'masquerade: yes')" ]]; then
          firewall-cmd --permanent --add-masquerade
          firewall-cmd --reload
        fi
      fi
    fi
  fi
}

function check_docker_start() {
  prepare_set_redhat_firewalld
  docker ps > /dev/null 2>&1
  if [[ "$?" != "0" ]]; then
    start_docker
  else
    echo_done
  fi
}

function init_docker() {
  echo_yellow "1. Install Docker"
  check_docker_install
  check_compose_install
  echo_yellow "\n2. Configure Docker"
  check_docker_config
  echo_yellow "\n3. Start Docker"
  check_docker_start
}


function image_has_prefix() {
  if [[ $1 =~ registry.* ]]; then
    echo "1"
  else
    echo "0"
  fi
}

function get_images() {
  version=$(get_current_version)
  images=(
    "547265870/redis:6-alpine"
    "547265870/mysql:5.7"
    "547265870/nginx:v1.12.2"
    "547265870/core:${version}"
  )
  for image in "${images[@]}"; do
    echo "${image}"
  done
}

function pull_images() {
  images=$(get_images)
  DOCKER_IMAGE_PREFIX=$(get_config DOCKER_IMAGE_PREFIX)
  i=1
  for image in ${images}; do
    echo "[${image}]"
    if [[ ! "$(docker images | grep $(echo ${image%:*}) | grep $(echo ${image#*:}))" ]]; then
      if [[ -n "${DOCKER_IMAGE_PREFIX}" && $(image_has_prefix "${image}") == "0" ]]; then
        docker pull "${DOCKER_IMAGE_PREFIX}/${image}"
        docker tag "${DOCKER_IMAGE_PREFIX}/${image}" "${image}"
        docker rmi -f "${DOCKER_IMAGE_PREFIX}/${image}"
      else
        docker pull "${image}"
      fi
    fi
    echo ""
    ((i++)) || true
  done
}

function load_images() {
  echo_yellow "\n4. Load images"
  pull_images
}


function init_config() {
  install_dir=$(get_config INSTALL_DIR)
  if [[ ! -d "${install_dir}" ]]; then
     mkdir -p ${install_dir}
     cp -a config/* ${install_dir}/
  fi

  if [[ ! -f .env ]]; then
    ln -s "${CONFIG_FILE}" .env
  fi
  echo_done
}

function perform_db_migrations() {
  version=$(get_config VERSION)
  compose_project_name=$(get_config COMPOSE_PROJECT_NAME)
  config_file=$(get_config CONFIG_FILE)
  
  docker run -i --rm --network=${compose_project_name}_net \
    --env-file=${config_file} \
    547265870/core:"${version}" init_db 
}

function init_db() {
  cmd="docker-compose -f ./compose/docker-compose-network.yml"
  cmd="${cmd} -f ./compose/docker-compose-mysql.yml"
  cmd="${cmd} -f ./compose/docker-compose-redis.yml"
  ${cmd} up -d
  if ! perform_db_migrations; then
    re_code="1"
  fi
  ${cmd} down
  echo
  if [[ "${re_code}" ]]; then
    log_error "Failed to change the table structure!"
    exit 1
  else
    echo_done
  fi
}


function config_bees {
  echo_yellow "\n5. Init Bees config"
  init_config
  echo_yellow "\n6. Init Bees Database" 
  init_db
}


function main() {
  init_docker
  load_images
  config_bees
}

if [[ "$0" == "${BASH_SOURCE[0]}" ]]; then
  main
fi
